package com.suray.basic.wcs.plc.pojo.oper.lifter;

import com.suray.basic.wcs.plc.core.Plc;
import com.suray.basic.wcs.plc.core.PlcOffset;
import com.suray.basic.wcs.plc.enums.Location;
import com.suray.basic.wcs.plc.enums.PlcDeviceType;
import com.suray.basic.wcs.plc.pojo.DeviceBase;
import com.suray.basic.wcs.plc.pojo.lifter.data.map.CarMap;
import com.suray.basic.wcs.plc.pojo.lifter.data.map.LifterMap;
import com.suray.basic.wcs.plc.utils.*;
import com.suray.basic.wcs.utils.Coord;
import com.suray.basic.wcs.utils.WcsFuncUtil;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 货叉式提升机（WCS控制）
 *
 * @author minj
 * @version 1.0
 */
public class ForkLifterOper extends LifterOper {
    public static Map<String, Boolean> lifterInterruptMap = new HashMap<>();
    private boolean permitClearTask = true;

    public boolean isPermitClearTask() {
        return permitClearTask;
    }

    public void setPermitClearTask(boolean permitClearTask) {
        this.permitClearTask = permitClearTask;
    }

    //提升机当前位移量
    private final static PlcOffset LIFTER_DIS_L = new PlcOffset(0, null);
    private final static PlcOffset LIFTER_DIS_H = new PlcOffset(1, null);

    public int getLifterDis() {
        return WcsFuncUtil.combineToDWord(readPlc(LIFTER_DIS_L), readPlc(LIFTER_DIS_H));
    }

    //提升机条码值
    private final static PlcOffset Lifter_GROUND_CODE = new PlcOffset(2, null);

    public int getLifterGroundCode() {
        return readPlc(Lifter_GROUND_CODE);
    }

    //校验位
    private final static PlcOffset LIFE = new PlcOffset(3, null);
    //两向车当前位移量
    private final static PlcOffset TWO_CAR_DIS_L = new PlcOffset(4, null);
    private final static PlcOffset TWO_CAR_DIS_H = new PlcOffset(5, null);

    public int getTwoCarDis() {
        return WcsFuncUtil.combineToDWord(readPlc(TWO_CAR_DIS_L), readPlc(TWO_CAR_DIS_H));
    }

    //两向车当前条码值
    private final static PlcOffset TWO_CAR_GROUND_CODE_L = new PlcOffset(6, null);
    private final static PlcOffset TWO_CAR_GROUND_CODE_H = new PlcOffset(7, null);

    public int getTwoCarGroundCode() {
        return WcsFuncUtil.combineToDWord(readPlc(TWO_CAR_GROUND_CODE_L), readPlc(TWO_CAR_GROUND_CODE_H));
    }

    //两向车升降当前位移量
    private final static PlcOffset TWO_CAR_PALLET_DIS_L = new PlcOffset(8, null);
    private final static PlcOffset TWO_CAR_PALLET_DIS_H = new PlcOffset(9, null);

    public int getTwoCarPalletDis() {
        return WcsFuncUtil.combineToDWord(readPlc(TWO_CAR_PALLET_DIS_L), readPlc(TWO_CAR_PALLET_DIS_H));
    }

    //四向车平台左光电
    private final static PlcOffset FOUR_CAR_LEFT_SIG = new PlcOffset(10, 0);

    public boolean isFourCarLeftSig() {
        return readPlc(FOUR_CAR_LEFT_SIG) == 1;
    }

    //四向车平台右光电
    private final static PlcOffset FOUR_CAR_RIGHT_SIG = new PlcOffset(10, 1);

    //平台检测四向车光电
    private final static PlcOffset HAS_FOUR_CAR_SIG = new PlcOffset(10, 2);
    //平台检测两向车光电
    private final static PlcOffset HAS_TWO_CAR_SIG = new PlcOffset(10, 3);

    public boolean hasTwoCarInLifter() {
        return readPlc(HAS_TWO_CAR_SIG) == 1;
    }

    //平台上限位开关
    private final static PlcOffset UP_LIMIT = new PlcOffset(10, 4);
    //平台下限位开关
    private final static PlcOffset DOWN_LIMIT = new PlcOffset(10, 5);
    //1轴使能状态
    private final static PlcOffset ZHOU_ENABLE_1 = new PlcOffset(10, 6);

    public boolean isZhouEnable1() {
        return readPlc(ZHOU_ENABLE_1) == 1;
    }

    //2轴使能状态
    private final static PlcOffset ZHOU_ENABLE_2 = new PlcOffset(10, 7);

    public boolean isZhouEnable2() {
        return readPlc(ZHOU_ENABLE_2) == 1;
    }

    //3轴使能状态
    private final static PlcOffset ZHOU_ENABLE_3 = new PlcOffset(10, 8);

    public boolean isZhouEnable3() {
        return readPlc(ZHOU_ENABLE_3) == 1;
    }

    //4轴使能状态
    private final static PlcOffset ZHOU_ENABLE_4 = new PlcOffset(10, 9);

    public boolean isZhouEnable4() {
        return readPlc(ZHOU_ENABLE_4) == 1;
    }

    //1轴报错状态
    private final static PlcOffset ZHOU_ERROR_1 = new PlcOffset(10, 10);

    public boolean isZhouError1() {
        return readPlc(ZHOU_ERROR_1) == 1;
    }

    //2轴报错状态
    private final static PlcOffset ZHOU_ERROR_2 = new PlcOffset(10, 11);

    public boolean isZhouError2() {
        return readPlc(ZHOU_ERROR_2) == 1;
    }

    //3轴报错状态
    private final static PlcOffset ZHOU_ERROR_3 = new PlcOffset(10, 12);

    public boolean isZhouError3() {
        return readPlc(ZHOU_ERROR_3) == 1;
    }

    //4轴报错状态
    private final static PlcOffset ZHOU_ERROR_4 = new PlcOffset(10, 13);

    public boolean isZhouError4() {
        return readPlc(ZHOU_ERROR_4) == 1;
    }

    //两向车平台左光电
    private final static PlcOffset TWO_CAR_LEFT_SIG = new PlcOffset(10, 14);

    public boolean isTwoCarLeftSig() {
        return readPlc(TWO_CAR_LEFT_SIG) == 1;
    }

    //两向车平台右光电
    private final static PlcOffset TWO_CAR_RIGHT_SIG = new PlcOffset(10, 15);

    public boolean isTwoCarRightSig() {
        return readPlc(TWO_CAR_RIGHT_SIG) == 1;
    }

    //两向车行驶轴使能状态
    private final static PlcOffset TWO_CAR_DRIVER_ENABLE = new PlcOffset(11, 0);

    public boolean isTwoCarDriverEnable() {
        return readPlc(TWO_CAR_DRIVER_ENABLE) == 1;
    }

    //两向车行驶轴报错状态
    private final static PlcOffset TWO_CAR_DRIVE_ERROR = new PlcOffset(11, 1);

    public boolean isTwoCarDriveError() {
        return readPlc(TWO_CAR_DRIVE_ERROR) == 1;
    }

    //两向车升降轴使能状态
    private final static PlcOffset TWO_CAR_PALLET_ENABLE = new PlcOffset(11, 2);

    public boolean isTwoCarPalletEnable() {
        return readPlc(TWO_CAR_PALLET_ENABLE) == 1;
    }

    //两向车升降轴报错状态
    private final static PlcOffset TWO_CAR_PALLET_ERROR = new PlcOffset(11, 3);

    public boolean isTwoCarPalletError() {
        return readPlc(TWO_CAR_PALLET_ERROR) == 1;
    }

    //1方向检测四向车光电信号
    private final static PlcOffset DIRECTION_1_CAR_SIG = new PlcOffset(11, 4);

    public boolean isDirection1CarSig() {
        return readPlc(DIRECTION_1_CAR_SIG) == 1;
    }

    //3方向检测四向车光电信号
    private final static PlcOffset DIRECTION_3_CAR_SIG = new PlcOffset(11, 5);

    public boolean isDirection3CarSig() {
        return readPlc(DIRECTION_3_CAR_SIG) == 1;
    }

    //1方向检测托盘光电信号
    private final static PlcOffset DIRECTION_1_PALLET_SIG = new PlcOffset(11, 6);

    public boolean isDirection1PalletSig() {
        return readPlc(DIRECTION_1_PALLET_SIG) == 1;
    }

    //3方向检测托盘光电信号
    private final static PlcOffset DIRECTION_3_PALLET_SIG = new PlcOffset(11, 7);

    public boolean isDirection3PalletSig() {
        return readPlc(DIRECTION_3_PALLET_SIG) == 1;
    }

    //4#1方向托盘光电
    private final static PlcOffset DIR_1_PALLET_SIG = new PlcOffset(11, 8);

    public boolean isDir1PalletSig() {
        return readPlc(FOUR_CAR_RIGHT_SIG) == 1;
    }

    //4#3方向托盘光电
    private final static PlcOffset DIR_3_PALLET_SIG = new PlcOffset(11, 9);

    public boolean isDir3PalletSig() {
        return readPlc(DIR_3_PALLET_SIG) == 1;
    }

    //2#托盘光电
    private final static PlcOffset DIR_2_PALLET_SIG = new PlcOffset(11, 10);

    public boolean isDir2PalletSig() {
        return readPlc(DIR_2_PALLET_SIG) == 1;
    }

    //凸轮光电信号1
    private final static PlcOffset CAM_SIG_1 = new PlcOffset(11, 11);

    public boolean isCamSig1() {
        return readPlc(CAM_SIG_1) == 1;
    }

    //凸轮光电信号2
    private final static PlcOffset CAM_SIG_2 = new PlcOffset(11, 12);

    public boolean isCamSig2() {
        return readPlc(CAM_SIG_2) == 1;
    }

    //凸轮限位开关信号
    private final static PlcOffset CAM_LIMIT = new PlcOffset(11, 13);

    public boolean isCamLimit() {
        return readPlc(CAM_LIMIT) == 1;
    }

    //行驶接触器
    private final static PlcOffset DRIVE_CONTACT = new PlcOffset(11, 14);

    public boolean isDriveContact() {
        return readPlc(DRIVE_CONTACT) == 1;
    }

    //升降接触器
    private final static PlcOffset UP_DOWN_CONTACT = new PlcOffset(11, 15);

    public boolean isUpDownContact() {
        return readPlc(UP_DOWN_CONTACT) == 1;
    }

    //5V电源
    private final static PlcOffset POWER_5 = new PlcOffset(12, 0);

    public boolean isPower5() {
        return readPlc(POWER_5) == 1;
    }

    //行驶刹车
    private final static PlcOffset DRIVE_BRAKE = new PlcOffset(12, 1);

    public boolean isDriveBrake() {
        return readPlc(DRIVE_BRAKE) == 1;
    }

    //电器盒加热
    private final static PlcOffset PLC_HEAT = new PlcOffset(12, 2);

    public boolean isPlcHeat() {
        return readPlc(PLC_HEAT) == 1;
    }

    //两向车行驶中
    private final static PlcOffset TWO_CAR_DRIVING = new PlcOffset(12, 3);

    public boolean isTwoCarDriving() {
        return readPlc(TWO_CAR_DRIVING) == 1;
    }

    //两向车托盘顶升到位
    private final static PlcOffset TWO_CAR_UP_OK = new PlcOffset(12, 4);

    public boolean isTwoCarUpOk() {
        return readPlc(TWO_CAR_UP_OK) == 1;
    }

    //两向车托盘下降到位
    private final static PlcOffset TWO_CAR_DOWN_OK = new PlcOffset(12, 5);

    public boolean isTwoCarDownOk() {
        return readPlc(TWO_CAR_DOWN_OK) == 1;
    }

    //Wcs可下发任务
    private final static PlcOffset CAN_DO_TASK = new PlcOffset(12, 6);
    //提升机运行中
    private final static PlcOffset LIFTER_RUNNING = new PlcOffset(12, 7);
    //任务执行中
    private final static PlcOffset TASKING = new PlcOffset(12, 8);

    public boolean isTasking() {
        return readPlc(TASKING) == 1;
    }

    //调试模式
    private final static PlcOffset DEBUG_MODE = new PlcOffset(12, 9);

    public boolean isDebugMode() {
        return readPlc(DEBUG_MODE) == 1;
    }

    //提升机已锁定
    private final static PlcOffset LIFTER_LOCK = new PlcOffset(12, 10);
    //提升机到位
    private final static PlcOffset LIFTER_ARRIVED = new PlcOffset(12, 11);

    //两向车到位
    private final static PlcOffset CAR_ARRIVED = new PlcOffset(12, 12);

    public boolean isCarArrived() {
        return readPlc(CAR_ARRIVED) == 1;
    }

    //故障代码
    private final static PlcOffset ERROR_CODE = new PlcOffset(14, null);

    public int getErrorCode() {
        return readPlc(ERROR_CODE);
    }

    //警告代码
    private final static PlcOffset WARN_CODE = new PlcOffset(15, null);

    public int getWarnCode() {
        return readPlc(WARN_CODE);
    }

    //任务完成ID号
    private final static PlcOffset FINISH_TASK_ID = new PlcOffset(16, null);

    //提升机当前层
    private final static PlcOffset CURRENT_LAYER = new PlcOffset(17, null);

    //两向车当前位置(A(0-9)：1,左对接；2，右对接；3提升机原点;B（0-99）:楼层;C（0-99）：1货位)
    private final static PlcOffset TWO_CAR_LOCATION = new PlcOffset(18, null);

    public int getTwoCarLocation() {
        return readPlc(TWO_CAR_LOCATION);
    }

    /**
     * 必须为1，否则错误
     *
     * @return
     */
    public int getTwoCarLocationSite() {
        return getTwoCarLocation() % 100;
    }

    /**
     * 两向车位置:1,左对接；2，右对接；3提升机原点
     *
     * @return
     */
    public int getTwoCarLocal() {
        return getTwoCarLocation() / 10000;
    }

    /**
     * 两向车楼层
     *
     * @return
     */
    public int getTwoCarLayer() {
        return getTwoCarLocation() / 100 % 100;
    }

    //当前执行任务
    private final static PlcOffset TASKING_ID = new PlcOffset(19, null);

    public int getTaskingId() {
        return readPlc(TASKING_ID);
    }

    //当前执行指令编号
    private final static PlcOffset TASKING_CMD_NO = new PlcOffset(20, null);

    public int getTaskingCmdNo() {
        return readPlc(TASKING_CMD_NO);
    }

    //指令完成编号
    private final static PlcOffset FINISH_CMD_NO = new PlcOffset(21, null);

    public int getFinishCmdNo() {
        return readPlc(FINISH_CMD_NO);
    }

    //行驶驱动器报警代码
    private final static PlcOffset DRIVING_ERROR_CODE = new PlcOffset(22, null);

    public int getDrivingErrorCode() {
        return readPlc(DRIVING_ERROR_CODE);
    }

    //升降驱动器报警代码
    private final static PlcOffset UP_DOWN_ERROR_CODE = new PlcOffset(23, null);

    //写给提升机的指令编号，不为0时不能写入
    private final static PlcOffset WRITE_CMD_NO = new PlcOffset(51, null);

    public int getWriteCmdNo() {
        return readPlc(WRITE_CMD_NO);
    }

    //写给提升机的任务编号，不为0时不能写入
    private final static PlcOffset WRITE_TASK_NO = new PlcOffset(52, null);

    public int getWriteTaskNo() {
        return readPlc(WRITE_TASK_NO);
    }

    public int getUpDownErrorCode() {
        return readPlc(UP_DOWN_ERROR_CODE);
    }

    /**
     * 清除提升机任务指令完成编号
     */
    public void clearLifterFinishTaskCmdNo() throws IOException {
        oper("清除提升机任务指令完成编号", this.getClass(), FINISH_CMD_NO.getAddressOffset(), 10, 0);
    }

    //任务操作
    private final static int LIFTER_ACTION = 36;

    /**
     * 暂停
     */
    public void sendPause() throws IOException {
        oper("暂停", this.getClass(), LIFTER_ACTION, 10, 1);
    }

    /**
     * 继续
     */
    public void sendContinue() throws IOException {
        oper("继续", this.getClass(), LIFTER_ACTION, 10, 2);
    }

    /**
     * 急停
     */
    public void sendStop() throws IOException {
        oper("急停", this.getClass(), LIFTER_ACTION, 10, 3);
    }

    /**
     * 清除任务
     */
    public void sendClearTask() throws IOException {
        oper("清除任务", this.getClass(), LIFTER_ACTION, 10, 4);
    }

    /**
     * 急停恢复
     */
    public void sendClearStop() throws IOException {
        oper("急停恢复", this.getClass(), LIFTER_ACTION, 10, 5);
    }

    //修改楼层高度命令号
    private final static int EDIT_LAYER_TYPE = 37;

    public void setLifterDis(int layer, int lifterDis) throws IOException {
        int[] data = new int[3];
        data[0] = layer;
        data[1] = lifterDis & 0xFFFF;
        data[2] = (lifterDis >> 16) & 0xFFFF;
        oper("设置提升机位移量", this.getClass(), EDIT_LAYER_TYPE, 10, data);
    }

    //修改两向车货位距离
    private final static int EDIT_TWO_CAR_SITE = 40;

    public void setCarDis(int layer, LifterLocationType locationType) throws IOException {
        int[] data = new int[5];
        switch (locationType) {
            case RIGHT:
                data[0] = 2 * 10000 + layer * 100 + 1;
                break;
            case LEFT:
                data[0] = 1 * 10000 + layer * 100 + 1;
                break;
            case INSIDE:
                return;
            default:
                throw new RuntimeException("错误的两向车货位类型：" + locationType);
        }
        int carDis = getTwoCarDis();
        data[1] = carDis & 0xFFFF;
        data[2] = (carDis >> 16) & 0xFFFF;
        int groundCode = getTwoCarGroundCode();
        data[3] = groundCode & 0xFFFF;
        data[4] = (groundCode >> 16) & 0xFFFF;
        oper("设置两向车位移量", this.getClass(), EDIT_TWO_CAR_SITE, 10, data);
    }
    //设置两向车位移量

    //设置小车托盘位移量
    public void setCarPalletDis(PalletStatus palletStatus) throws IOException {
        int[] data = new int[3];
        switch (palletStatus) {
            case UP:
                data[0] = 3 * 10000 + 1 * 100 + 1;
                break;
            case DOWN:
                data[0] = 4 * 10000 + 1 * 100 + 1;
                break;
            default:
                throw new RuntimeException("错误的托盘状态：" + palletStatus);
        }
        int palletDis = getTwoCarPalletDis();
        data[1] = palletDis & 0xFFFF;
        data[2] = (palletDis >> 16) & 0xFFFF;
        oper("设置小车托盘位移量", this.getClass(), EDIT_TWO_CAR_SITE, 10, data);
    }

    //设置原点
    private final static int SET_ORIGINAL = 45;

    //设置小车原点
    public void setCarOriginal() throws IOException {
        oper("设置小车原点", this.getClass(), SET_ORIGINAL, 10, 21);
    }

    //设置小车托盘原点
    public void setCarPalletOriginal() throws IOException {
        oper("设置小车托盘原点", this.getClass(), SET_ORIGINAL, 10, 31);
    }

    //设置提升机原点
    public void setLifterOriginal() throws IOException {
        oper("设置提升机原点", this.getClass(), SET_ORIGINAL, 10, 11);
    }

    //故障恢复
    private final static int RECOVERY_LIFTER = 46;
    //锁定提升机
    private final static int LOCK_LIFTER = 47;
    //调试模式
    private final static int CHANGE_DEBUG_MODE = 49;

    /**
     * 切换模式
     *
     * @param isDebugMode：true 调试模式，false 正常模式
     */
    public void changeMode(boolean isDebugMode) throws IOException {
        oper("切换提升机模式", this.getClass(), CHANGE_DEBUG_MODE, 10, isDebugMode ? 1 : 0);
    }

    //手动模式
    private final static int MANUAL_CONTROL = 50;

    //手动控制
    public void manualControl(ManualMode manualMode) throws IOException {
        oper("手动控制提升机", this.getClass(), MANUAL_CONTROL, 10, manualMode.getValue());
    }

    //任务指令编号
    private final static int SEND_CMD_NO = 51;

    /**
     * 发送行驶指令
     *
     * @param cmdNo
     * @param segment
     * @return
     */
    public void sendSegment(int cmdNo, int segment) throws IOException {
        oper("发送行驶指令", this.getClass(), SEND_CMD_NO, 10, cmdNo * 100 + segment);
    }

    //下发整体任务
    private final static int SEND_TASK = 52;

    public void sendWholeTask(int taskId, List<LifterTask> tasks) throws IOException {
        int[] data = new int[tasks.size() * 5 + 1];
        data[0] = taskId;
        int i = 1;
        for (LifterTask task : tasks) {
            data[i++] = task.getTaskType().getValue();
            data[i++] = task.getStart() & 0xFFFF;
            data[i++] = (task.getStart() >> 16) & 0xFFFF;
            data[i++] = task.getEnd() & 0xFFFF;
            data[i++] = (task.getEnd() >> 16) & 0xFFFF;
        }
        oper("下发整体任务", this.getClass(), SEND_TASK, 10, data);
    }

    /**
     * 托盘升的位移量
     *
     * @return
     */
    public Integer getPalletUpDis() {
        if (palletStatusMap.get(PalletStatus.UP) == null) {
            return null;
        }
        return palletStatusMap.get(PalletStatus.UP).distance;
    }

    /**
     * 托盘降的位移量
     *
     * @return
     */
    public Integer getPalletDownDis() {
        if (palletStatusMap.get(PalletStatus.DOWN) == null) {
            return null;
        }
        return palletStatusMap.get(PalletStatus.DOWN).distance;
    }

    /**
     * 穿梭车进入提升机的位移量
     *
     * @return
     */
    public Integer getCarInLifterDis() {
        return getCarDistance(1, LifterLocationType.INSIDE);
    }

    /**
     * 提升机左侧位移量（两向车进出提升机）
     *
     * @return
     */
    public Integer[] getLeftLocationDis() {
        Integer[] leftLifterDis = new Integer[getGridzMax()];
        for (int i = 0; i < getGridzMax(); i++) {
            leftLifterDis[i] = getCarDistance(i + 1, LifterLocationType.LEFT);
        }
        return leftLifterDis;
    }

    /**
     * 提升机右侧位移量（两向车进出提升机）
     *
     * @return
     */
    public Integer[] getRightLocationDis() {
        Integer[] rightLifterDis = new Integer[getGridzMax()];
        for (int i = 0; i < getGridzMax(); i++) {
            rightLifterDis[i] = getCarDistance(i + 1, LifterLocationType.RIGHT);
        }
        return rightLifterDis;
    }

    /**
     * 两向车层的位移量 垂直方向
     *
     * @return
     */
    public Integer[] getTwoCarLayerDis() {
        Integer[] twoCarLayerLifterDis = new Integer[getGridzMax()];
        for (int i = 0; i < getGridzMax(); i++) {
            twoCarLayerLifterDis[i] = getLifterDistance(i + 1, LifterLayerType.TWO_CAR_LAYER);
        }
        return twoCarLayerLifterDis;
    }

    /**
     * 四向车层的位移量  垂直方向
     *
     * @return
     */
    public Integer[] getFourCarLayerDis() {
        Integer[] fourCarLayerLifterDis = new Integer[getGridzMax()];
        for (int i = 0; i < getGridzMax(); i++) {
            fourCarLayerLifterDis[i] = getLifterDistance(i + 1, LifterLayerType.FOUR_CAR_LAYER);
        }
        return fourCarLayerLifterDis;
    }


    /**
     * 获取提升机垂直方向上每层的位移量
     *
     * @param layer
     * @param type
     * @return
     */
    public Integer getLifterDistance(int layer, LifterLayerType type) {
        switch (type) {
            case TWO_CAR_LAYER:
                return getLifterDistance(false, layer);
            case FOUR_CAR_LAYER:
                return getLifterDistance(true, layer);
            case INVALID_LAYER:
                return getLifterDis();
            default:
                throw new RuntimeException("提升机层类型错误:" + type);
        }
    }

    /**
     * 获取提升机垂直方向上每层的位移量
     *
     * @param isFourLayer 是否是四向车层
     * @param layer       层
     * @return
     */
    protected Integer getLifterDistance(boolean isFourLayer, int layer) {
        try {
            int floor = LifterMap.combineLayer(layer, isFourLayer);
            if (lifterLayerMap.get(floor) == null) {
                return null;
            }
            return lifterLayerMap.get(floor).distance;
        } catch (Exception e) {
            throw new RuntimeException("请配置提升机位移量：四向车层？" + isFourLayer + ", " + layer + "层");
        }
    }

    /**
     *  根据层和位置获取坐标
     * @param layer
     * @param locationType
     * @return
     */
    public Coord getNode(int layer, LifterLocationType locationType) {
        for (CarMap carMap : carLocationMap.values()) {
            if (carMap.lifterLocationType == locationType) {
                if (locationType == LifterLocationType.INSIDE && carMap.node.getZ() == 1) {
                    Coord node = new Coord(carMap.node);
                    node.setZ(layer);
                    return node;
                }

                if (carMap.node.getZ() == layer) {
                    return carMap.node;
                }
            }
        }
        throw new RuntimeException("请设置两向车的位移量：" + layer + "层，" + locationType);
    }

    /**
     * 获取提升机每一层两侧水平方向的位移量
     *
     * @param layer
     * @param locationType
     * @return
     */
    public Integer getCarDistance(int layer, LifterLocationType locationType) {
        for (CarMap carMap : carLocationMap.values()) {
            if (carMap.lifterLocationType == locationType) {
                if (locationType == LifterLocationType.INSIDE && carMap.node.getZ() == 1) {
                    return carMap.distance;
                }

                if (carMap.node.getZ() == layer) {
                    return carMap.distance;
                }
            }
        }
//        throw new RuntimeException("请设置两向车位移量：" + layer + "层，" + locationType);
        return null;
    }

    public int getCarDistance(Coord node) {
        try {
            return carLocationMap.get(node).distance;
        } catch (Exception e) {
//            LifterLog.exceptionLog(LoggerType.WARN, null, series, e, this.getClass());
            throw new RuntimeException("未配置两向车位置：" + node);
        }
    }

    public int getPalletDistance(PalletStatus palletStatus) {
        try {
            return palletStatusMap.get(palletStatus).distance;
        } catch (Exception e) {
//            LifterLog.exceptionLog(LoggerType.WARN, null, series, e, this.getClass());
            throw new RuntimeException("请配置托盘位移量：" + palletStatus);
        }
    }

    public ForkLifterOper(PlcDeviceType plcDeviceType, int startNo, String deviceName, int deviceNo, Coord coord,
                          Location location, Coord lockLocation, long deviceId, Integer gridzMax,
                          Integer gridzRelative, int plcId) {
        super(plcDeviceType, startNo, deviceName, deviceNo, coord, location, lockLocation,
                deviceId, gridzMax, gridzRelative, plcId);
    }


    public LifterLocationType analyzeLocation(int location) {
        Location local = Location.parseLocationCode(location);
        return analyzeLocation(local);
    }

    public LifterLocationType analyzeLocation(Location location) {
        switch (location) {
            case LEFT:
                return LifterLocationType.LEFT;
            case RIGHT:
                return LifterLocationType.RIGHT;
            case INSIDE:
                return LifterLocationType.INSIDE;
            default:
                throw new RuntimeException("提升机位置错误:" + location);
        }
    }

    /**
     * 获取提升机当前任务编号
     *
     * @return
     */
    public int getHoistCurrentTaskNo() {
        return readPlc(TASKING_ID);
    }

    /**
     * 获取提升机完成编号
     *
     * @return
     */
    public int getHoistFinalTaskNo() {
        return readPlc(FINISH_TASK_ID);
    }

    /**
     * 提升机当前层信息
     *
     * @return 0表示非平层
     */
    public int getHoistCurrentLayerInfo() {
        return readPlc(CURRENT_LAYER);
    }

    /**
     * 提升机当前层
     *
     * @return
     */
    public int getHoistCurrentLayer() {
        return getHoistCurrentLayerInfo() % 100;
    }

    /**
     * 提升机层类型
     *
     * @return
     */
    public LifterLayerType getHoistLayerType() {
        return LifterLayerType.parseLocal(getHoistCurrentLayerInfo() / 100);
    }

    /**
     * 心跳信号(1-60循环）
     *
     * @return
     */
    public int getCheckNo() {
        return readPlc(LIFE);
    }

    /**
     * 运行状态
     *
     * @param floor    层 提升机内部的层传1-10任意数字
     * @param location 位置
     * @return true 运行
     */
    public boolean isFacilityExisted(Integer floor, Location location) {
        return false;
    }

    /**
     * 是否为自动模式
     *
     * @return true 自动 false 非自动
     */
    public boolean isAutoMode() {
        return true;
    }

    /**
     * 提升机是否就绪
     *
     * @return true为已就绪
     */
    public boolean isReady() {
        return readPlc(CAN_DO_TASK) == 1;
    }

    /**
     * 确认提升机内有车
     *
     * @return true为有车
     */
    public boolean isHaveShuttle() {
        return readPlc(HAS_FOUR_CAR_SIG) == 1;
    }

    /**
     * 提升机运行状态
     *
     * @return true为运行中
     */
    public boolean isRuning() {
        return readPlc(LIFTER_RUNNING) == 1;
    }

    /**
     * 确认提升机是否到位
     *
     * @return true为已到位
     */
    public boolean isArrived() {
        return readPlc(LIFTER_ARRIVED) == 1;
    }

    /**
     * 确认提升机内有无货物
     *
     * @return true 为有货
     */
    public boolean isHaveCargo() {
        return hasTwoCarInLifter() && isDir2PalletSig();
    }

    /**
     * 确认提升机货物是否到位
     *
     * @return true为已到位
     */
    public boolean isHoistGoodArrived() {
        return hasTwoCarInLifter() && isDir2PalletSig() && isCarArrived();
    }

    /**
     * 确认提升机是否未阻挡
     *
     * @return true为未阻挡
     */
    public boolean isHoistBarrierPass() {
        return false;
    }

    /**
     * 确认提升机内部输送线未运行
     *
     * @return true为未运行
     */
    public boolean isHoistConveyInsideStop() {
        return !isTwoCarDriving();
    }

    /**
     * 确认提升机本地远程
     *
     * @return true 远程
     */
    public boolean isRemoteMode() {
        return true;
    }

    /**
     * 确认锁状态
     *
     * @return true 锁定
     */

    public boolean lockState() {
        return readPlc(LIFTER_LOCK) == 1;
    }

    // 故障模块

    /**
     * 故障：提升机前限位超限
     *
     * @return true 为故障
     */
    public boolean isHoistFontLimited() {
        return false;
    }

    /**
     * 故障：提升机后限位超限
     *
     * @return true 为故障
     */
    public boolean isHoistBackLimited() {
        return false;
    }

    /**
     * 故障：提升机上限位超限
     *
     * @return true 为故障
     */
    public boolean isHoistUpLimited() {
        return false;
    }

    /**
     * 故障：提升机下限位超限
     *
     * @return true 为故障
     */
    public boolean isHoistDownLimited() {
        return false;
    }

    /**
     * 故障：提升机条码读取异常
     *
     * @return true 为故障
     */
    public boolean isHoistBarReadCorrect() {
        return false;
    }

    /**
     * 故障：提升机条码范围异常
     *
     * @return true 为故障
     */
    public boolean isHoistBarRangeCorrect() {
        return false;
    }

    /**
     * 故障:电子警报
     *
     * @return true 故障
     */
    public boolean isAlarm() {
        return getErrorCode() > 0;
    }

    /**
     * 故障：提升机任务字非法
     *
     * @return true为故障
     */
    public boolean isHoistTaskCodeCorrect() {
        return false;
    }

    /**
     * 故障：提升机起点位置无货
     *
     * @return true为故障
     */
    public boolean isHoistStartEmpty() {
        return getErrorCode() == 10053;
    }

    /**
     * 故障：提升机终点位置有货
     *
     * @return true为故障
     */
    public boolean isHoistEndEmpty() {
        return getErrorCode() == 10054;
    }

    /**
     * 故障：提升机平台内有货
     *
     * @return true为故障
     */
    public boolean isHoistInStock() {
        return false;
    }

    /**
     * 故障：小车未到位
     *
     * @return true 为故障
     */
    public boolean isHoistShuttleArrived() {
        return getErrorCode() == 100;
    }

    /**
     * 故障：小车未驶离
     *
     * @return true 为故障
     */
    public boolean isHoistShuttleOuted() {
        return getErrorCode() == 101;
    }

    /**
     * 提升机内链条机前边缘超限
     *
     * @return true 故障
     */
    public boolean isChainFontError() {
        return false;
    }

    /**
     * 提升机内链条机后边缘超限
     *
     * @return true 故障
     */
    public boolean isChainBackError() {
        return false;
    }

    /**
     * 边缘超限
     *
     * @return true 故障
     */

    public boolean isEdgeTransfinite() {
        return false;
    }

    /**
     * WCS清理提升机任务完成编号
     *
     * @return
     */
    public void setHoistFinalTaskNoClear() throws IOException {
        oper("WCS清理提升机任务完成编号", this.getClass(), FINISH_TASK_ID.getAddressOffset(), 10, 0);
    }

    /**
     * 清除当前提升机任务
     * w
     *
     * @return
     */
    public void setHoistTaskClear() throws IOException {
        oper("清除当前提升机任务", this.getClass(), LIFTER_ACTION, 10, 4);
    }

    /**
     * 清除当前提升机故障
     *
     * @return
     */
    public void setHoistCurrentErrorClear() throws IOException {
        oper("清除当前提升机故障", this.getClass(), RECOVERY_LIFTER, 10, 1);
    }

    /**
     * 提升机上锁
     */
    public void lockHoist(int password) throws IOException {
        int[] data = new int[2];
        data[0] = 1;
        data[1] = password;
        oper("提升机上锁", this.getClass(), LOCK_LIFTER, 10, data);
    }

    /**
     * 提升机解锁
     */
    public void unlockHoist(int password) throws IOException {
        int[] data = new int[2];
        data[0] = 0;
        data[1] = password;
        oper("提升机解锁", this.getClass(), LOCK_LIFTER, 10, data);
    }

    /**
     * 获取是否有错误，0为无错
     *
     * @return 0为无错
     */
    public int getError() {
        return getErrorCode();
    }

    public int readBit() {
        return 0;
    }

    /**
     * 提升机未就绪wcs下发任务 true 故障
     */
    public boolean notReadyHoist() {
        return false;
    }

    /**
     * wcs锁定失败 true 故障
     */
    public boolean lockProblem() {
        return false;
    }

    /**
     * 解锁失败
     *
     * @return true 故障
     */
    public boolean unlockProblem() {
        return false;
    }

    /**
     * 与主控断开 return true 故障
     */
    public boolean disconnect() {
        return false;
    }

    /**
     * 链条机故障 return true 故障
     */
    public boolean chainFault() {
        return false;
    }

    /**
     * 辊道机故障 return true 故障
     */
    public boolean rollerTableFault() {
        return false;
    }

    /**
     * 移栽升降机故障 return true 故障
     */
    public boolean transplantLiftFailure() {
        return false;
    }

    /**
     * 提升机前限位超限
     *
     * @return
     */
    public boolean overFrontLimit() {
        return false;
    }

    /**
     * 提升机后限位超限
     *
     * @return
     */
    public boolean overBackLimit() {
        return false;
    }

    /**
     * 提升机上限位超限
     *
     * @return
     */
    public boolean overUpLimit() {
        return readPlc(UP_LIMIT) == 1;
    }

    /**
     * 提升机下限位超限
     *
     * @return
     */
    public boolean overDownLimit() {
        return readPlc(DOWN_LIMIT) == 1;
    }

    /**
     * 扫码读取故障
     *
     * @return
     */
    public boolean scanFault() {
        return false;
    }

    /**
     * 扫码数值范围错误
     *
     * @return
     */
    public boolean scanNumRangeFault() {
        return false;
    }

    /**
     * 伺服报警
     *
     * @return
     */
    public boolean servoFault() {
        return false;
    }

    /**
     * 提升机任务字非法
     *
     * @return
     */
    public boolean lifterTaskNoIllegal() {
        return false;
    }

    /**
     * 提升机起始位置无货
     *
     * @return
     */
    public boolean noCargoStartLocation() {
        return false;
    }

    /**
     * 提升机终点位置有货
     *
     * @return
     */
    public boolean hasCargoEndLocation() {
        return false;
    }

    /**
     * 提升机内有货
     *
     * @return
     */
    public boolean hasCargoInnerLifter() {
        return false;
    }

    /**
     * 小车未到位
     *
     * @return
     */
    public boolean rgvNotArrived() {
        return getErrorCode() == 100;
    }

    /**
     * 小车未驶离
     *
     * @return
     */
    public boolean rgvNotLeave() {
        return getErrorCode() == 101;
    }

    /**
     * 提升机内链条机前边缘超限
     *
     * @return
     */
    public boolean lifterOverChainFrontLimit() {
        return false;
    }

    /**
     * 提升机内链条机后边缘超限
     *
     * @return
     */
    public boolean lifterOverChainBackLimit() {
        return false;
    }

    /**
     * 对接链条机边缘超限
     *
     * @return
     */
    public boolean overConnectChainLimit() {
        return false;
    }

    /**
     * 提升机是否故障
     *
     * @return
     */
    public boolean isLifterFault() {
        return getErrorCode() > 0;
    }

    /**
     * 获取提升机的Z坐标
     *
     * @param x
     * @param y
     * @return
     */
    public static int getGridz(int x, int y) {
        Integer gridz = 1;
        Map<Coord, DeviceBase> deviceLifterCoordMaps = Plc.deviceLifterCoordMap;
        if (deviceLifterCoordMaps != null) {
            for (Coord coordMapKeys : deviceLifterCoordMaps.keySet()) {
                if (coordMapKeys.getX() == x && coordMapKeys.getY() == y) {
                    gridz = coordMapKeys.getZ();
                }
            }
        }
        return gridz;
    }
}
